#!/usr/bin/python2
# -*- coding: utf-8 -*-

import re
import sys

from ryu.base import app_manager
from ryu.cmd.manager import main
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER, CONFIG_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_3, ofproto_v1_3_parser
from ryu.topology import switches

from lib.topo import Topo
from lib.executor2 import SequentialExecutor
from lib.executor_merge2 import PartialExecutor

from eventlet import Queue
from eventlet import sleep

from lib.hedera.hedera import Hedera
from lib.hedera.FatTreeSim import FatTreeSim

from ryu.lib.hub import spawn

from ryuapp.lib.hedera.mock_update_gen import MockUpdateGenerator



class TestApp(app_manager.RyuApp):
    OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
    _CONTEXTS = {'switches': switches.Switches}

    def __init__(self, *args, **kwargs):
        super(TestApp, self).__init__(*args, **kwargs)
        self.__switches = kwargs['switches']
        self.__notify_queue = Queue()
        self.__pre_update_1()

    @set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER)
    def _flow_stats_reply_handler(self, ev):
        print("========_flow_stats_reply_handler=========")
        msg = ev.msg
        from ryu.ofproto.ofproto_v1_3_parser import OFPFlowStatsReply
        assert isinstance(msg, OFPFlowStatsReply)
        self.__notify_queue.put(msg)

    @set_ev_cls(ofp_event.EventOFPFlowRemoved, MAIN_DISPATCHER)
    def _flow_removed_handler(self, ev):
        print("========_flow_removed_handler=========")
        msg = ev.msg
        from ryu.ofproto.ofproto_v1_3_parser import OFPFlowRemoved
        assert isinstance(msg, OFPFlowRemoved)
        self.__notify_queue.put(msg)

    @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
    def _packet_in_handler(self, ev):
        pass

    def __pre_update(self):
        update_queue = Queue()
        install_queue = Queue()
        reply_queue = Queue()
        self.__topo = FatTreeSim(install_queue,reply_queue,2)
        self.__executor = SequentialExecutor(update_queue, install_queue, reply_queue)
        self.__update_generator = MockUpdateGenerator(update_queue, self.__topo, 2)

        def run(t):
            t.run()

        spawn(run,self.__topo)
        spawn(run,self.__executor)
        spawn(run,self.__update_generator)

    def __pre_update_1(self):
        common_queue = Queue()
        install_queue = Queue()
        self.__topo = FatTreeSim(install_queue,common_queue,2)
        self.__executor = PartialExecutor(common_queue, install_queue)
        self.__update_generator = MockUpdateGenerator(common_queue, self.__topo, 2)

        def run(t):
            t.run()

        spawn(run,self.__topo)
        spawn(run,self.__executor)
        spawn(run,self.__update_generator)


#######################################


if __name__ == 'hederatest':
    pass
    # app_manager.require_app("ryu.topology.switches")
    # app_manager.require_app("ryu.app.gui_topology.gui_topology")

if __name__ == '__main__':
    sys.argv.append(sys.argv[0].split('/')[-1])
    # sys.argv.append('--verbose')
    sys.argv.append('--enable-debugger')
    # sys.argv.append('--observe-links')
    # sys.argv.append('--user-flags')
    # sys.argv.append('testapp_flags.py')
    # sys.argv.append('--test_lambda')
    # sys.argv.append('.1')
    sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
    sys.exit(main())
